package com.gw.booking.service;

import com.alibaba.fastjson.JSONObject;
import com.gw.booking.common.ApiException;
import com.gw.booking.common.Constant;
import com.gw.booking.common.MessageCode;
import com.gw.booking.common.WXAppletUserInfo;
import com.gw.booking.dto.wechat.WCustomerDtoOut;
import com.gw.booking.dto.wechat.WLoginDtoOut;
import com.gw.booking.entity.Customer;
import com.gw.booking.entity.LoginToken;
import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.InvocationTargetException;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;


@Service
public class CustomerService {
    @Autowired
    private SessionFactory sessionFactory;
    @Autowired
    private LoginTokenService loginTokenService;

    public WLoginDtoOut txLogin(String code, String ip) {
        Session session = sessionFactory.getCurrentSession();
        JSONObject jsonObject = WXAppletUserInfo.getSessionKeyOropenidForDiner(code);
        String openId = jsonObject.get("openid") == null ? null : jsonObject.get("openid").toString();
        if (openId == null) {
            throw new ApiException(MessageCode.CODE_WXCODE_ERROR);
        }
        Customer customer = (Customer) session.createQuery("from Customer where openId = :openId")
                .setParameter("openId", openId).uniqueResult();
        if (customer == null) {
            customer = new Customer();
            customer.setOpenId(openId);
            customer.setType(Constant.USER_TYPE_DINER);
            session.save(customer);
        }
        LoginToken loginToken = loginTokenService.txAddLoginToken(session, customer.getType(), customer.getId(), ip, null);
        WLoginDtoOut wLoginDtoOut = new WLoginDtoOut();
        wLoginDtoOut.setCustomerId(customer.getId());
        wLoginDtoOut.setNickname(customer.getNickName());
        wLoginDtoOut.setToken(loginToken.getToken());
        wLoginDtoOut.setType(customer.getType());
        return wLoginDtoOut;
    }

    public WCustomerDtoOut profile(LoginToken loginToken) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        Customer customer = (Customer) session.get(Customer.class, loginToken.getUserId());
        if (customer == null) {
            throw new ApiException(MessageCode.CODE_NO_USER);
        }
        WCustomerDtoOut wCustomerDtoOut = new WCustomerDtoOut();
        PropertyUtils.copyProperties(wCustomerDtoOut, customer);
        return wCustomerDtoOut;
    }

    public void txUpdateName(LoginToken loginToken, String name) {
        Session session = sessionFactory.getCurrentSession();
        Customer customer = (Customer) session.get(Customer.class, loginToken.getUserId());
        customer.setName(name);
        session.update(customer);
        session.flush();
    }

    public void txUpdatePhone(LoginToken loginToken, String phone) {
        Session session = sessionFactory.getCurrentSession();
        Customer customer = (Customer) session.get(Customer.class, loginToken.getUserId());
        customer.setPhone(phone);
        session.update(customer);
        session.flush();
    }

    public static String wxDecrypt(String encrypted, String session_key, String iv) {
        String json = null;
        byte[] encrypted64 = Base64.decodeBase64(encrypted);
        byte[] key64 = Base64.decodeBase64(session_key);
        byte[] iv64 = Base64.decodeBase64(iv);
        byte[] data;
        try {
            init();
            json = new String(decrypt(encrypted64, key64, generateIV(iv64)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return json;
    }

    /**
     * 初始化密钥
     */
    public static void init() throws Exception {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        KeyGenerator.getInstance("AES").init(128);
    }

    /**
     * 生成iv
     */
    public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
        // iv 为一个 16 字节的数组，这里采用和 iOS 端一样的构造方法，数据全为0
        // Arrays.fill(iv, (byte) 0x00);
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    }

    /**
     * 生成解密
     */
    public static byte[] decrypt(byte[] encryptedData, byte[] keyBytes, AlgorithmParameters iv)
            throws Exception {
        Key key = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        // 设置为解密模式
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        return cipher.doFinal(encryptedData);
    }
}
